package validate

import (
	"regexp"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestIsASCII(t *testing.T) {
	tests := []struct {
		input    string
		expected bool
	}{
		{"", true},
		{"Hello, World!", true},
		{"こんにちは", false},
		{"Hello, こんにちは", false},
		{"1234567890", true},
		{"!@#$%^&*()", true},
		{"😊", false},
		{"ASCII😊", false},
	}

	for _, test := range tests {
		result := IsASCII(test.input)
		if result != test.expected {
			t.Errorf("IsASCII(%q) = %v; want %v", test.input, result, test.expected)
		}
	}
}
func TestIsInt(t *testing.T) {
	as := assert.New(t)
	as.Equal(IsInt("-0"), true)
	as.Equal(IsInt("+0"), true)
	as.Equal(IsInt("-1"), true)
	as.Equal(IsInt("+1"), true)
	as.Equal(IsInt("0"), true)
	as.Equal(IsInt("1"), true)
	as.Equal(IsInt("22"), true)
	as.Equal(IsInt("333"), true)

	as.Equal(IsInt("12024433"), true)
	as.Equal(IsInt("-123012123"), true)
	as.Equal(IsInt(""), false)
	as.Equal(IsInt("05 23"), false)
	as.Equal(IsInt("1a23"), false)
	as.Equal(IsInt("1.8585"), false)
	as.Equal(IsInt("100这23"), false)
	as.Equal(IsInt("-"), false)
	as.Equal(IsInt("0125423453"), false)
	as.Equal(IsInt("1e6"), true)
	as.Equal(IsInt("2e+6"), true)
	as.Equal(IsInt("-1e6"), true)

	as.Equal(IsUint("0"), true)
	as.Equal(IsUint("125423453"), true)
	as.Equal(IsUint("-125423453"), false)

	as.Equal(IsUint("1e6"), true)
	as.Equal(IsUint("2e+6"), true)
	as.Equal(IsUint("-1e6"), false)

	as.Equal(IsIntWithDecimal("127", 8, true), true)
	as.Equal(IsIntWithDecimal("-128", 8, true), true)
	as.Equal(IsIntWithSN("127", 8, true), true)
	as.Equal(IsIntWithSN("-128", 8, true), true)

	as.Equal(IsIntWithDecimal("128", 8, true), false)
	as.Equal(IsIntWithDecimal("-129", 8, true), false)
	as.Equal(IsIntWithSN("128", 8, true), false)
	as.Equal(IsIntWithSN("-129", 8, true), false)

	as.Equal(IsIntWithDecimal("0", 8, false), true)
	as.Equal(IsIntWithDecimal("255", 8, false), true)
	as.Equal(IsIntWithDecimal("-1", 8, false), false)
	as.Equal(IsIntWithDecimal("256", 8, false), false)
	as.Equal(IsIntWithSN("0", 8, false), true)
	as.Equal(IsIntWithSN("2.55e2", 8, false), true)
	as.Equal(IsIntWithSN("-1e0", 8, false), false)
	as.Equal(IsIntWithSN("256", 8, false), false)

	as.Equal(IsIntWithDecimal("32767", 16, true), true)
	as.Equal(IsIntWithDecimal("-32768", 16, true), true)
	as.Equal(IsIntWithDecimal("32768", 16, true), false)
	as.Equal(IsIntWithDecimal("-32769", 16, true), false)
	as.Equal(IsIntWithDecimal("0", 16, false), true)
	as.Equal(IsIntWithDecimal("65535", 16, false), true)
	as.Equal(IsIntWithDecimal("-1", 16, false), false)
	as.Equal(IsIntWithDecimal("65536", 16, false), false)

	as.Equal(IsIntWithSN("32767", 16, true), true)
	as.Equal(IsIntWithSN("-32768", 16, true), true)
	as.Equal(IsIntWithSN("32768", 16, true), false)
	as.Equal(IsIntWithSN("-32769", 16, true), false)
	as.Equal(IsIntWithSN("0", 16, false), true)
	as.Equal(IsIntWithSN("65535", 16, false), true)
	as.Equal(IsIntWithSN("-1", 16, false), false)
	as.Equal(IsIntWithSN("65536", 16, false), false)

	as.Equal(IsIntWithDecimal("2147483647", 32, true), true)
	as.Equal(IsIntWithDecimal("-2147483648", 32, true), true)
	as.Equal(IsIntWithDecimal("2147483648", 32, true), false)
	as.Equal(IsIntWithDecimal("-2147483649", 32, true), false)
	as.Equal(IsIntWithDecimal("0", 32, false), true)
	as.Equal(IsIntWithDecimal("4294967295", 32, false), true)
	as.Equal(IsIntWithDecimal("-1", 32, false), false)
	as.Equal(IsIntWithDecimal("4294967296", 32, false), false)

	as.Equal(IsIntWithSN("2147483647", 32, true), true)
	as.Equal(IsIntWithSN("-2147483648", 32, true), true)
	as.Equal(IsIntWithSN("2147483648", 32, true), false)
	as.Equal(IsIntWithSN("-2147483649", 32, true), false)
	as.Equal(IsIntWithSN("0", 32, false), true)
	as.Equal(IsIntWithSN("4294967295", 32, false), true)
	as.Equal(IsIntWithSN("-1", 32, false), false)
	as.Equal(IsIntWithSN("4294967296", 32, false), false)

	as.Equal(IsIntWithDecimal("9223372036854775807", 64, true), true)
	as.Equal(IsIntWithDecimal("-9223372036854775808", 64, true), true)
	as.Equal(IsIntWithDecimal("9223372036854775808", 64, true), false)
	as.Equal(IsIntWithDecimal("-9223372036854775809", 64, true), false)
	as.Equal(IsIntWithDecimal("0", 64, false), true)
	as.Equal(IsIntWithDecimal("18446744073709551615", 64, false), true)
	as.Equal(IsIntWithDecimal("-1", 64, false), false)
	as.Equal(IsIntWithDecimal("18446744073709551616", 64, false), false)

	as.Equal(IsIntWithSN("9223372036854775.807e3", 64, true), true)
	as.Equal(IsIntWithSN("-9223372036854775.808E+3", 64, true), true)
	as.Equal(IsIntWithSN("9223372036854775808", 64, true), false)
	as.Equal(IsIntWithSN("-9223372036854775809", 64, true), false)
	as.Equal(IsIntWithSN("0", 64, false), true)
	as.Equal(IsIntWithSN("18446744073709551615", 64, false), true)
	as.Equal(IsIntWithSN("-1", 64, false), false)
	as.Equal(IsIntWithSN("18446744073709551616", 64, false), false)

}
func TestIsFloat(t *testing.T) {
	as := assert.New(t)
	as.Equal(IsFloat("0"), true)
	as.Equal(IsFloat("+0"), true)
	as.Equal(IsFloat("12"), true)
	as.Equal(IsFloat("-21"), true)
	as.Equal(IsFloat("0.21"), true)
	as.Equal(IsFloat("-0.21"), true)
	as.Equal(IsFloat("1213.21"), true)
	as.Equal(IsFloat("-31.21"), true)
	as.Equal(IsFloat("12414.000"), true)
	as.Equal(IsFloat(""), false)
	as.Equal(IsFloat("-"), false)
	as.Equal(IsFloat("-0"), true)
	as.Equal(IsFloat("001.3"), false)
	as.Equal(IsFloat("01.23453"), false)
	as.Equal(IsFloat("1 -2张414.0"), false)
	as.Equal(IsFloat("1 -2414.0"), false)
	as.Equal(IsFloat("1 2414.0"), false)
	as.Equal(IsFloat("1e6"), true)
	as.Equal(IsFloat("-1e6"), true)
	as.Equal(IsUfloat("1E-6"), true)
	as.Equal(IsUfloat("-1e+6"), false)
	as.Equal(IsFloat("-1E+06"), true)
	as.Equal(IsUfloat("1E+6"), true)

	// 限制小数位数
	as.Equal(IsFloatWithDecimal("0.21", 2, true), true)
	as.Equal(IsFloatWithSN("123e-2", 2, true), true) // 123e-2 =>  1.23
}
func TestIsLetter(t *testing.T) {
	as := assert.New(t)
	as.Equal(IsLetterWith("aNdfsfsgsrCVdf", 0, 0, 0), true)
	as.Equal(IsLetterWith("dfafaf", 1, 0, 0), true)
	as.Equal(IsLetterWith("dfa", 1, 0, 3), true)
	as.Equal(IsLetterWith("AVX", 2, 0, 3), true)
	as.Equal(IsLetterWith("aNdfsfsgsrCVdf", 1, 0, 0), false)
	as.Equal(IsLetterWith("dfFafaf", 2, 0, 0), false)
	as.Equal(IsLetterWith("aNPd", 0, 0, 3), false)
	as.Equal(IsLetterWith("dffa", 0, 0, 3), false)
	as.Equal(IsLetterWith("a0NPd", 0, 0, 0), false)
	as.Equal(IsLetterWith("df-=fa", 0, 0, 0), false)
	as.Equal(IsLetterWith("56445641", 0, 1, 0), true)
	as.Equal(IsLetterWith("56445641", 0, 2, 0), false)
	as.Equal(IsLetterWith("5FSFSGFSG6445641", 0, 1, 0), true)
	as.Equal(IsLetterWith("FSFSGFSG6445641", 0, 2, 0), true)
	as.Equal(IsLetterWith("564FSGAGA45641", 0, 2, 0), false)
	as.Equal(IsLetterWith("564-415-641", 0, 1, 0, "-"), true)
	as.Equal(IsLetterWith("afa_F05_641", 0, 2, 11, "-_"), true)
}
func TestMatchNumberSNToDecimal(t *testing.T) {
	tests := []struct {
		input string
		want  string
		ok    bool
	}{
		{"", "", false},
		{"0", "0", true},
		{"0.", "", false},
		{".0", "", false},
		{"+", "", false},
		{"-", "", false},
		{"123", "123", true},
		{"+123", "+123", true},
		{"-12.30", "-12.30", true},
		{"1.2345e+04", "12345", true},
		{"1.23e-2", "0.0123", true},
		{"5e3", "5000", true},
		{"-5e3", "-5000", true},
		{"123e-2", "1.23", true},
		{"0.0012e-3", "0.0000012", true},
		{"12345e-5", "0.12345", true},
		{"+1e4", "+10000", true},
		{"1234E-5", "0.01234", true},
		{"1234.5e+0", "1234.5", true},
		{"1e-3", "0.001", true},
		{"0.1e-3", "0.0001", true},
	}

	for _, tc := range tests {
		got, ok := MatchNumberSNToDecimal(tc.input)
		if !tc.ok {
			if ok {
				t.Errorf("input(%s) Expected false, got: true", tc.input)
			}
		} else {
			if !ok {
				t.Fatalf("input(%s) Expected true, got: false", tc.input)
			}
			if got != tc.want {
				t.Errorf("input(%s) Expected %s, got %s", tc.input, tc.want, got)
			} else {
				t.Logf("input(%s) =>  %s", tc.input, got)
			}
		}
	}
}

// go test -bench=. -benchmem
func BenchmarkIsInt(b *testing.B) {
	as := assert.New(b)
	for n := 0; n < b.N; n++ {
		as.Equal(IsInt("0"), true)
		as.Equal(IsInt("12028487487814433"), true)
		as.Equal(IsInt("-123012123"), true)
		as.Equal(IsInt(""), false)
		as.Equal(IsInt("05 23"), false)
		as.Equal(IsInt("1a23"), false)
		as.Equal(IsInt("1.8585"), false)
		as.Equal(IsInt("100这23"), false)
		as.Equal(IsInt("-"), false)
		as.Equal(IsInt("-0"), false)
		as.Equal(IsInt("0125423453"), false)
	}
}
func BenchmarkIsInt_Regexp(b *testing.B) {
	as := assert.New(b)
	reg := regexp.MustCompile(`^(0|-?[1-9]\d*)$`)
	for n := 0; n < b.N; n++ {
		as.Equal(reg.MatchString("0"), true)
		as.Equal(reg.MatchString("12028487487814433"), true)
		as.Equal(reg.MatchString("-123012123"), true)
		as.Equal(reg.MatchString(""), false)
		as.Equal(reg.MatchString("05 23"), false)
		as.Equal(reg.MatchString("1a23"), false)
		as.Equal(reg.MatchString("1.8585"), false)
		as.Equal(reg.MatchString("100这23"), false)
		as.Equal(reg.MatchString("0125423453"), false)
	}
}
func BenchmarkIsFloat(b *testing.B) {
	as := assert.New(b)
	for n := 0; n < b.N; n++ {
		as.Equal(IsFloat("0"), true)
		as.Equal(IsFloat("12"), true)
		as.Equal(IsFloat("-21"), true)
		as.Equal(IsFloat("0.21"), true)
		as.Equal(IsFloat("-0.21"), true)
		as.Equal(IsFloat("1213.21"), true)
		as.Equal(IsFloat("-31.21"), true)
		as.Equal(IsFloat("12414.000"), true)
		as.Equal(IsFloat("-"), false)
		as.Equal(IsFloat("-0"), false)
		as.Equal(IsFloat("01.23453"), false)
		as.Equal(IsFloat("1 -2张414.0"), false)
		as.Equal(IsFloat("1 -2414.0"), false)
		as.Equal(IsFloat("1 2414.0"), false)
		as.Equal(IsFloat("+3"), true)
	}
}
func BenchmarkIsFloat_Regexp(b *testing.B) {
	as := assert.New(b)
	reg := regexp.MustCompile(`^(0|-?(0\.\d+|[1-9]+\d*\.?\d*|[1-9]\d*))$`)

	for n := 0; n < b.N; n++ {
		as.Equal(reg.MatchString("0"), true)
		as.Equal(reg.MatchString("12"), true)
		as.Equal(reg.MatchString("-21"), true)
		as.Equal(reg.MatchString("0.21"), true)
		as.Equal(reg.MatchString("-0.21"), true)
		as.Equal(reg.MatchString("1213.21"), true)
		as.Equal(reg.MatchString("-31.21"), true)
		as.Equal(reg.MatchString("12414.000"), true)

		as.Equal(reg.MatchString(""), false)
		as.Equal(reg.MatchString("-"), false)
		as.Equal(reg.MatchString("-0"), false)
		as.Equal(reg.MatchString("001.3"), false)
		as.Equal(reg.MatchString("01.23453"), false)
		as.Equal(reg.MatchString("1 -2张414.0"), false)
		as.Equal(reg.MatchString("1 -2414.0"), false)
		as.Equal(reg.MatchString("1 2414.0"), false)
		as.Equal(reg.MatchString("+3"), false)
	}
}
func BenchmarkIsLetter(b *testing.B) {
	as := assert.New(b)
	for n := 0; n < b.N; n++ {
		as.Equal(IsLetterWith("aNdfsfsgsrCVdf", 0, 0, 0), true)
		as.Equal(IsLetterWith("dfafaf", 1, 0, 0), true)
		as.Equal(IsLetterWith("dfa", 1, 0, 3), true)
		as.Equal(IsLetterWith("AVX", 2, 0, 3), true)
		as.Equal(IsLetterWith("aNdfsfsgsrCVdf", 1, 0, 0), false)
		as.Equal(IsLetterWith("dfFafaf", 2, 0, 0), false)
		as.Equal(IsLetterWith("aNPd", 0, 0, 3), false)
		as.Equal(IsLetterWith("dffa", 0, 0, 3), false)
		as.Equal(IsLetterWith("a0NPd", 0, 0, 0), false)
		as.Equal(IsLetterWith("df-=fa", 0, 0, 0), false)
		as.Equal(IsLetterWith("56445641", 0, 1, 0), true)
		as.Equal(IsLetterWith("56445641", 0, 2, 0), false)
		as.Equal(IsLetterWith("5FSFSGFSG6445641", 0, 1, 0), true)
		as.Equal(IsLetterWith("FSFSGFSG6445641", 0, 2, 0), true)
		as.Equal(IsLetterWith("564FSGAGA45641", 0, 2, 0), false)
		as.Equal(IsLetterWith("564-415-641", 0, 1, 0, "-"), true)
		as.Equal(IsLetterWith("afa_F05_641", 0, 2, 11, "-_"), true)
	}
}
